//
//  tdl/meta/btypes.h
//  Created by tommy on 13/02/06.
//	

#ifndef tdl_meta_btypes_h
#define tdl_meta_btypes_h

namespace tdl {
///////////////
struct null_type;

struct empty_type {};

template <int v> struct int2type
{
	enum { value = v };
};

template <typename T> struct type2type
{
	typedef T type;
};

template <typename T> struct null_tpl_type;

// type_selector
template <typename T, typename U, bool s> struct type_selector;
template <typename T, typename U> struct type_selector<T, U, true>
{
	typedef T type;
	typedef U dummy;
};

template <typename T, typename U> struct type_selector<T, U, false>
{
	typedef U type;
	typedef T dummy;
};

// type_conversion
template <typename T, typename U> struct type_conversion
{
private:
	typedef char small;
	struct big { char dummy[2]; };
	static small Test(U);
	static big Test(...);
	static T MakeT();
public:
	enum { can_convert = sizeof(Test(MakeT())) == sizeof(small) };
	enum { same_type = false };
};
template <typename T> struct type_conversion<T, T>
{
	enum { can_convert = 1, same_type = 1 };
};
template <typename U> struct type_conversion<null_type, U>
{
	enum { can_convert = 0, same_type = 0 };
};
template <> struct type_conversion<null_type, null_type>
{
	enum { can_convert = 0, same_type = 0 };
};

// is_same_type
template <typename T, typename U> struct is_same_type
{
	enum { value = type_conversion<T, U>::same_type };
};

// is_super_sub_class
template <typename T, typename U> struct is_super_sub_class
{
	enum { value = (type_conversion<const U*, const T*>::can_convert && !type_conversion<const T*, const void*>::same_type) };
};

// type list
template <typename T, typename U> struct type_list
{
	typedef T head;
	typedef U tail;
};

// macros for making type_list easily
#define TYPELIST_1(T1) type_list<T1, null_type>
#define TYPELIST_2(T1, T2) type_list<T1, TYPELIST_1(T2) >
#define TYPELIST_3(T1, T2, T3) type_list<T1, TYPELIST_2(T2, T3) >
#define TYPELIST_4(T1, T2, T3, T4) type_list<T1, TYPELIST_3(T2, T3, T4) >
#define TYPELIST_5(T1, T2, T3, T4, T5) type_list<T1, TYPELIST_4(T2, T3, T4, T5) >
#define TYPELIST_6(T1, T2, T3, T4, T5, T6) type_list<T1, TYPELIST_5(T2, T3, T4, T5, T6) >
#define TYPELIST_7(T1, T2, T3, T4, T5, T6, T7) type_list<T1, TYPELIST_6(T2, T3, T4, T5, T6, T7) >
#define TYPELIST_8(T1, T2, T3, T4, T5, T6, T7, T8) type_list<T1, TYPELIST_7(T2, T3, T4, T5, T6, T7, T8) >
#define TYPELIST_9(T1, T2, T3, T4, T5, T6, T7, T8, T9) type_list<T1, TYPELIST_8(T2, T3, T4, T5, T6, T7, T8, T9) >
#define TYPELIST_10(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) type_list<T1, TYPELIST_9(T2, T3, T4, T5, T6, T7, T8, T9, T10) >

// template for making type_list which is more readable than macros
template <
	typename T1 =  null_type, typename T2 =  null_type, typename T3 =  null_type, typename T4 =  null_type,
	typename T5 =  null_type, typename T6 =  null_type, typename T7 =  null_type, typename T8 =  null_type,
	typename T9 =  null_type, typename T10 = null_type, typename T11 = null_type, typename T12 = null_type,
	typename T13 = null_type, typename T14 = null_type, typename T15 = null_type, typename T16 = null_type, 
	typename T17 = null_type, typename T18 = null_type, typename T19 = null_type, typename T20 = null_type>
struct make_type_list
{
private:
	typedef typename make_type_list<T2, T3, T4, T5, T6, T7, T8, T9, T10, 
		T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>::type tail_type;
public:
	typedef type_list<T1, tail_type> type;
};

template <> 
struct make_type_list<
	null_type, null_type, null_type, null_type, null_type, 
	null_type, null_type, null_type, null_type, null_type, 
	null_type, null_type, null_type, null_type, null_type, 
	null_type, null_type, null_type, null_type, null_type>
{
	typedef null_type type;
};

/////////////////
}	// namespace tdl

#endif

